package cn.tedu.mall.seckill.service.impl;

import cn.tedu.mall.common.exception.CoolSharkServiceException;
import cn.tedu.mall.common.pojo.domain.CsmallAuthenticationInfo;
import cn.tedu.mall.common.restful.ResponseCode;
import cn.tedu.mall.order.service.IOmsOrderService;
import cn.tedu.mall.pojo.order.dto.OrderAddDTO;
import cn.tedu.mall.pojo.order.dto.OrderItemAddDTO;
import cn.tedu.mall.pojo.order.vo.OrderAddVO;
import cn.tedu.mall.pojo.seckill.dto.SeckillOrderAddDTO;
import cn.tedu.mall.pojo.seckill.model.SeckillSuccess;
import cn.tedu.mall.pojo.seckill.vo.SeckillCommitVO;
import cn.tedu.mall.seckill.config.RabbitMqComponentConfiguration;
import cn.tedu.mall.seckill.service.ISeckillService;
import cn.tedu.mall.seckill.utils.SeckillCacheUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

@Service
@Slf4j
public class SeckillServiceImpl implements ISeckillService {
    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @DubboReference
    private IOmsOrderService dubboOmsOrderService;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Override
    public SeckillCommitVO commitSeckill(SeckillOrderAddDTO seckillOrderAddDTO) {
        //第一部分：利用Redis去检查是否重复购买和库存是否充足
        //检查是否重复购买利用userId和skuId实现
        Long userId = getUserId();
        Long skuId = seckillOrderAddDTO.getSeckillOrderItemAddDTO().getSkuId();
        //userId和skuId组合，去获取key
        String reseckillCheckKey = SeckillCacheUtils.getReseckillCheckKey(skuId, userId);
        //使用increment()方法，如果key值已经存在，直接在value中+1，
        // 比如value为1，那么调用increment方法之后，会返回给用户2的值
        //如果key不存在，就存储该key，并把值设为1，返回给用户
        Long increment = stringRedisTemplate.boundValueOps(reseckillCheckKey).increment();
        //判断increment是否大于1，大于1就是重复购买
        if(increment>1)
            throw new CoolSharkServiceException(ResponseCode.BAD_REQUEST,"当前商品不能重复购买");
        //程序到此处就是第一次购买，检查库存是否充足
        //先获取对应的key
        String stockKey = SeckillCacheUtils.getStockKey(skuId);
        //使用decrement(),减少对应key的value，默认减1
        Long decrement = stringRedisTemplate.boundValueOps(stockKey).decrement();
        //decrement不小于0，就是库存充足
        if(decrement<0) {
            //将重复购买的值减去1
            stringRedisTemplate.boundValueOps(reseckillCheckKey).decrement();
            throw new CoolSharkServiceException(ResponseCode.BAD_REQUEST, "对不起，商品已售罄");
        }
        //第二部分：将秒杀订单转成普通订单
        OrderAddDTO orderAddDTO = covertSeckillOrderToOrder(seckillOrderAddDTO);
        //赋值userId
        orderAddDTO.setUserId(userId);
        //利用Dubbo调用Order模块中的方法，生成普通订单
        OrderAddVO orderAddVO = dubboOmsOrderService.addOrder(orderAddDTO);
        //第三部分：将秒杀成功的信息保存到消息队列中
        SeckillSuccess seckillSuccess = new SeckillSuccess();
        seckillSuccess.setSeckillId(orderAddVO.getId());
        seckillSuccess.setUserId(userId);
        seckillSuccess.setUserPhone(orderAddDTO.getMobilePhone());
        seckillSuccess.setSkuId(skuId);
        seckillSuccess.setTitle(seckillOrderAddDTO.getSeckillOrderItemAddDTO().getTitle());
        seckillSuccess.setMainPicture(seckillOrderAddDTO.getSeckillOrderItemAddDTO().getMainPicture());
        seckillSuccess.setSeckillPrice(seckillOrderAddDTO.getSeckillOrderItemAddDTO().getPrice());
        seckillSuccess.setQuantity(seckillOrderAddDTO.getSeckillOrderItemAddDTO().getQuantity());
        seckillSuccess.setGmtCreate(orderAddVO.getCreateTime());
        seckillSuccess.setOrderSn(orderAddVO.getSn());
        //发送到RabbitMQ中
        rabbitTemplate.convertAndSend(RabbitMqComponentConfiguration.SECKILL_EX,
                RabbitMqComponentConfiguration.SECKILL_RK,seckillSuccess);
        //声明当前方法的返回值类型
        SeckillCommitVO seckillCommitVO = new SeckillCommitVO();
        BeanUtils.copyProperties(orderAddVO,seckillCommitVO);
        return seckillCommitVO;
    }

    private OrderAddDTO covertSeckillOrderToOrder(SeckillOrderAddDTO seckillOrderAddDTO) {
        //需要声明OrderAddDTO对象
        OrderAddDTO orderAddDTO = new OrderAddDTO();
        //同名属性赋值
        BeanUtils.copyProperties(seckillOrderAddDTO,orderAddDTO);
        //准备订单项
        List<OrderItemAddDTO> orderItemAddDTOList = new ArrayList<>();
        //把SeckillOrderAddDTO对象中的订单项，赋值给OrderItemAddDTO
        OrderItemAddDTO orderItemAddDTO = new OrderItemAddDTO();
        BeanUtils.copyProperties(seckillOrderAddDTO.getSeckillOrderItemAddDTO(),orderItemAddDTO);
        orderItemAddDTOList.add(orderItemAddDTO);
        orderAddDTO.setOrderItems(orderItemAddDTOList);
        return orderAddDTO; //这是普通订单中需要的参数
    }

    //获取当前登录用户的信息
    public CsmallAuthenticationInfo getUserInfo(){
        //利用SpringSecurity上下文对象获取
        UsernamePasswordAuthenticationToken token =
                (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
        //判断token是否为null
        if (token==null)
            throw new CoolSharkServiceException(ResponseCode.UNAUTHORIZED,"没有登录信息");

        //获取用户信息
       CsmallAuthenticationInfo userInfo = (CsmallAuthenticationInfo) token.getCredentials();
       return userInfo;
    }
    //获取用户id
    public Long getUserId(){
        return getUserInfo().getId();
    }
}
